package net.simflow.swf.analyzer.chart;

import java.util.ArrayList;
import java.util.Map.Entry;

import net.simflow.swf.analyzer.data.StringConstant;
import net.simflow.swf.analyzer.data.TupleStrInt;
import net.simflow.swf.analyzer.exec.data.ExecResult;
import net.simflow.swf.analyzer.exec.data.TaskExecResult;
import net.simflow.swf.analyzer.network.data.Flow;
import net.simflow.swf.analyzer.network.data.Service;

public class ExecResultChart {
	private static final int MAX_RESULT_LINE = 2000;

	private static ExecResultChart instance = new ExecResultChart();

	private ExecResultChart() {
	}

	public static ExecResultChart getInstance() {
		return instance;
	}

	public ArrayList<TupleStrInt> generate(String style, ExecResult eresult) {
		switch (style) {
		case ExecResult.ORIGINAL_EXECUTION_RESULT:
			return this.getOriExecResultString(eresult);
		case ExecResult.TOTAL_STEP:
			return this.getTotalStepString(eresult);
		case ExecResult.FLOW_CREATION_SPEED:
			return this.getFlowCreationSpeedString(eresult);
		case ExecResult.SERVICE_SCHEDULE:
			return this.getServiceScheduleString(eresult);
		case ExecResult.SERVICE_ABILITY:
			return this.getServiceAbilityString(eresult);
		case ExecResult.FLOW_RELDEADLINE:
			return this.getFlowRelDeadlineString(eresult);
		case ExecResult.FLOW_WEIGHT:
			return this.getFlowWeightString(eresult);
		}
		return null;
	}

	public ArrayList<TupleStrInt> generate(String style, ExecResult eresult,
			Flow flow) {
		switch (style) {
		case ExecResult.ORIGINAL_EXECUTION_RESULT:
			return this.getOriExecResultString(eresult, flow);
		case ExecResult.TOTAL_STEP:
			return this.getTotalStepString(eresult, flow);
		case ExecResult.FLOW_CREATION_SPEED:
			return this.getFlowCreationSpeedString(eresult, flow);
		case ExecResult.SERVICE_SCHEDULE:
			return this.getServiceScheduleString(eresult, flow);
		case ExecResult.SERVICE_ABILITY:
			return this.getServiceAbilityString(eresult, flow);
		case ExecResult.FLOW_RELDEADLINE:
			return this.getFlowRelDeadlineString(eresult, flow);
		case ExecResult.FLOW_WEIGHT:
			return this.getFlowWeightString(eresult, flow);
		}
		return null;
	}

	private ArrayList<TupleStrInt> getOriExecResultString(ExecResult eresult) {
		if (eresult.getTaskExecMap() == null) {
			return null;
		}
		eresult.getTaskExecMap().comparator();

		ArrayList<TupleStrInt> info = new ArrayList<TupleStrInt>();
		int totalCount = 0;
		int successCount = 0;
		int unfinishedCount = 0;
		for (Entry<Integer, TaskExecResult> en1 : eresult.getTaskExecMap()
				.entrySet()) {

			if (totalCount < MAX_RESULT_LINE) {
				info.add(new TupleStrInt(en1.getValue().getInfo(),
						StringConstant.CONTENT));
			} else if (totalCount == MAX_RESULT_LINE) {
				info.add(new TupleStrInt("...", StringConstant.CONTENT));
			}

			totalCount++;
			if (en1.getValue().getEndTime() != -1) {
				successCount++;
			} else {
				unfinishedCount++;
			}

		}

		if (info.isEmpty()) {
			return null;
		}

		info.add(0, new TupleStrInt(ExecResult.ORIGINAL_EXECUTION_RESULT
				+ ": Total " + totalCount + ": Succeess " + successCount
				+ ": Unfinish " + unfinishedCount, StringConstant.TITLE));
		return info;
	}

	private ArrayList<TupleStrInt> getOriExecResultString(ExecResult eresult,
			Flow flow) {
		if (eresult.getTaskExecMap() == null) {
			return null;
		}
		eresult.getTaskExecMap().comparator();

		ArrayList<TupleStrInt> info = new ArrayList<TupleStrInt>();
		int totalCount = 0;
		int successCount = 0;
		int unfinishedCount = 0;
		for (Entry<Integer, TaskExecResult> en1 : eresult.getTaskExecMap()
				.entrySet()) {
			TaskExecResult res = en1.getValue();
			if (res.getFlow() == flow) {
				if (totalCount < MAX_RESULT_LINE) {
					info.add(new TupleStrInt(res.getInfo(),
							StringConstant.CONTENT));
				} else if (totalCount == MAX_RESULT_LINE) {
					info.add(new TupleStrInt("...", StringConstant.CONTENT));
				}
				totalCount++;
				if (res.getEndTime() != -1) {
					successCount++;
				} else {
					unfinishedCount++;
				}
			}
		}

		if (info.isEmpty()) {
			return null;
		}

		info.add(0, new TupleStrInt(ExecResult.ORIGINAL_EXECUTION_RESULT
				+ ": Total " + totalCount + ": Succeess " + successCount
				+ ": Unfinish " + unfinishedCount, StringConstant.TITLE));
		return info;
	}

	private ArrayList<TupleStrInt> getFlowCreationSpeedString(ExecResult eresult) {
		ArrayList<TupleStrInt> info = new ArrayList<TupleStrInt>();
		info.add(new TupleStrInt(ExecResult.FLOW_CREATION_SPEED,
				StringConstant.TITLE));
		info.add(new TupleStrInt(String.valueOf(eresult.getFlowCreateSpeed()),
				StringConstant.CONTENT));
		return info;
	}

	private ArrayList<TupleStrInt> getFlowCreationSpeedString(
			ExecResult eresult, Flow flow) {
		ArrayList<TupleStrInt> info = new ArrayList<TupleStrInt>();
		info.add(new TupleStrInt(ExecResult.FLOW_CREATION_SPEED,
				StringConstant.TITLE));
		info.add(new TupleStrInt(String.valueOf(eresult.getFlowCreateSpeed()),
				StringConstant.CONTENT));
		return info;
	}

	private ArrayList<TupleStrInt> getTotalStepString(ExecResult eresult) {
		ArrayList<TupleStrInt> info = new ArrayList<TupleStrInt>();
		info.add(new TupleStrInt(ExecResult.TOTAL_STEP, StringConstant.TITLE));
		info.add(new TupleStrInt(String.valueOf(eresult.getTotalStep()),
				StringConstant.CONTENT));
		return info;
	}

	private ArrayList<TupleStrInt> getTotalStepString(ExecResult eresult,
			Flow flow) {
		ArrayList<TupleStrInt> info = new ArrayList<TupleStrInt>();
		info.add(new TupleStrInt(ExecResult.TOTAL_STEP, StringConstant.TITLE));
		info.add(new TupleStrInt(String.valueOf(eresult.getTotalStep()),
				StringConstant.CONTENT));
		return info;
	}

	private ArrayList<TupleStrInt> getServiceScheduleString(ExecResult eresult) {
		if (eresult.getServiceScheduleMap() == null) {
			return null;
		}

		ArrayList<TupleStrInt> info = new ArrayList<TupleStrInt>();
		for (Entry<Service, Integer> en1 : eresult.getServiceScheduleMap()
				.entrySet()) {
			info.add(new TupleStrInt(en1.getKey().getNameInNetwork() + ": "
					+ en1.getValue(), StringConstant.CONTENT));
		}

		if (info.isEmpty()) {
			return null;
		}

		info.add(0, new TupleStrInt(ExecResult.SERVICE_SCHEDULE,
				StringConstant.TITLE));
		return info;
	}

	private ArrayList<TupleStrInt> getServiceAbilityString(ExecResult eresult) {
		if (eresult.getServiceAbilityMap() == null) {
			return null;
		}

		ArrayList<TupleStrInt> info = new ArrayList<TupleStrInt>();
		for (Entry<Service, Integer> en1 : eresult.getServiceAbilityMap()
				.entrySet()) {
			info.add(new TupleStrInt(en1.getKey().getNameInNetwork() + ": "
					+ en1.getValue(), StringConstant.CONTENT));
		}

		if (info.isEmpty()) {
			return null;
		}

		info.add(0, new TupleStrInt(ExecResult.SERVICE_ABILITY,
				StringConstant.TITLE));
		return info;
	}

	private ArrayList<TupleStrInt> getServiceScheduleString(ExecResult eresult,
			Flow flow) {
		if (eresult.getServiceScheduleMap() == null) {
			return null;
		}

		ArrayList<TupleStrInt> info = new ArrayList<TupleStrInt>();
		for (Service svc : flow.getServiceSet()) {
			info.add(new TupleStrInt(svc.getNameInNetwork() + ": "
					+ eresult.getServiceScheduleMap().get(svc),
					StringConstant.CONTENT));
		}

		if (info.isEmpty()) {
			return null;
		}

		info.add(0, new TupleStrInt(ExecResult.SERVICE_SCHEDULE,
				StringConstant.TITLE));
		return info;
	}

	private ArrayList<TupleStrInt> getServiceAbilityString(ExecResult eresult,
			Flow flow) {
		if (eresult.getServiceAbilityMap() == null) {
			return null;
		}

		ArrayList<TupleStrInt> info = new ArrayList<TupleStrInt>();
		for (Service svc : flow.getServiceSet()) {
			info.add(new TupleStrInt(svc.getNameInNetwork() + ": "
					+ eresult.getServiceAbilityMap().get(svc),
					StringConstant.CONTENT));
		}

		if (info.isEmpty()) {
			return null;
		}

		info.add(0, new TupleStrInt(ExecResult.SERVICE_ABILITY,
				StringConstant.TITLE));
		return info;
	}

	private ArrayList<TupleStrInt> getFlowRelDeadlineString(ExecResult eresult) {
		if (eresult.getFlowRelDeadlineMap() == null) {
			return null;
		}

		ArrayList<TupleStrInt> info = new ArrayList<TupleStrInt>();
		for (Entry<Flow, Integer> en1 : eresult.getFlowRelDeadlineMap()
				.entrySet()) {
			info.add(new TupleStrInt(en1.getKey().getNameInNetwork() + ": "
					+ en1.getValue(), StringConstant.CONTENT));
		}

		if (info.isEmpty()) {
			return null;
		}

		info.add(0, new TupleStrInt(ExecResult.FLOW_RELDEADLINE,
				StringConstant.TITLE));
		return info;
	}

	private ArrayList<TupleStrInt> getFlowWeightString(ExecResult eresult) {
		if (eresult.getFlowWeightMap() == null) {
			return null;
		}

		ArrayList<TupleStrInt> info = new ArrayList<TupleStrInt>();
		for (Entry<Flow, Integer> en1 : eresult.getFlowWeightMap().entrySet()) {
			info.add(new TupleStrInt(en1.getKey().getNameInNetwork() + ": "
					+ en1.getValue(), StringConstant.CONTENT));
		}

		if (info.isEmpty()) {
			return null;
		}

		info.add(0, new TupleStrInt(ExecResult.FLOW_WEIGHT,
				StringConstant.TITLE));
		return info;
	}

	private ArrayList<TupleStrInt> getFlowRelDeadlineString(ExecResult eresult,
			Flow flow) {
		if (eresult.getFlowRelDeadlineMap() == null) {
			return null;
		}

		ArrayList<TupleStrInt> info = new ArrayList<TupleStrInt>();
		info.add(new TupleStrInt(ExecResult.FLOW_RELDEADLINE,
				StringConstant.TITLE));
		info.add(new TupleStrInt(flow.getNameInNetwork() + ": "
				+ eresult.getFlowRelDeadlineMap().get(flow),
				StringConstant.CONTENT));
		return info;
	}

	private ArrayList<TupleStrInt> getFlowWeightString(ExecResult eresult,
			Flow flow) {
		if (eresult.getFlowWeightMap() == null) {
			return null;
		}

		ArrayList<TupleStrInt> info = new ArrayList<TupleStrInt>();
		info.add(new TupleStrInt(ExecResult.FLOW_WEIGHT, StringConstant.TITLE));
		info.add(new TupleStrInt(flow.getNameInNetwork() + ": "
				+ eresult.getFlowWeightMap().get(flow), StringConstant.CONTENT));
		return info;
	}
}
